use alloc::fmt::format;
use alloc::{format, vec};
use alloc::vec::Vec;
use alloc::collections::btree_map::BTreeMap;
use core::ptr::{read, read_volatile, write_volatile};
use crate::dev::uart::Uart;

const PCI_ECAM : usize = 0x30000000usize;
const PCI_PIO : usize = 0x3000000usize;



fn init_vga( ad : *mut u32) {
    unsafe{
        write_volatile(ad.add(1),0x7u32);
        
        write_volatile(ad.add(4 + 0),0x70000000u32);
        
        write_volatile(ad.add(4 + 2),0x7E000000u32);
    }
}



pub fn register_pci_devices() {
    type PciHdler = fn(*mut u32);
    
    let pci_registery: Vec<(PciHdler, u32)> = vec![
        (init_vga, 0x11111234u32),
    ];
    
    
    
    let mut registered_devices : BTreeMap<u32,PciHdler> = BTreeMap::new();
    
    for entry in pci_registery {
        registered_devices.insert(entry.1,entry.0);
    }
    
    let ecam_base: u32 = PCI_ECAM as u32;
    
    for dev in 0..32{
        unsafe {
            let dev_addr = ((dev << 11) + ecam_base) as *mut u32;
            let dev_id = read_volatile(dev_addr);
            
            if  dev_id == 0xffffffffu32  {continue;}
            
            match registered_devices.get(&dev_id) {
                Some(hdlr) => {
                    hdlr(dev_addr);
                }
                None => {
                    let s = format!("Unregistered PCI ID : {:8x} @addr {:x}.\n",
                                    dev_id, dev_addr as u32);
                    Uart::get().write(s.as_bytes(),s.len());
                }
            }

        }
    }
}


// Legacy PIO com
pub unsafe fn pio_w16(addr : usize, val : u16) {
    write_volatile((PCI_PIO+addr) as *mut u16, val as u16);
}

pub unsafe fn pio_r16(addr : usize) -> u16{
    read_volatile(addr as *mut u16)
}